package github.sf.fw.utils;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Stream;

import static github.sf.fw.utils.StrUtil.underscoreName;

/**
 * 构建对象的Insert语句
 */
public class ObjSqlBuilder<T> {
    private final Class<T> objType;
    private final String tableName;
    private final List<Field> sqlFields = new ArrayList<Field>();
    private final StringBuilder partSql = new StringBuilder();

    /**
     * * @param objType   待构建对象的类型
     * * @param tableName 表名
     * * @tparam T 类型
     */
    public ObjSqlBuilder(Class<T> objType, String tableName) {
        this.objType = objType;
        this.tableName = tableName;
        initBuilder();
    }

    private void initBuilder() {
        if (objType == null) {
            throw new IllegalArgumentException("传入的对象不能为空");
        }
        Field[] fields = objType.getDeclaredFields();
        Stream.of(fields)
            .filter(field -> {
                String name = field.getName();
                boolean hasGetMethod = true;
                try {
                    objType.getMethod("get" + StringUtils.capitalize(name));
                } catch (NoSuchMethodException ex) {
                    hasGetMethod = false;
                }
                boolean hasSetMethod = true;
                try {
                    objType.getMethod("Set" + StringUtils.capitalize(name), field.getType());
                } catch (NoSuchMethodException ex) {
                    hasSetMethod = false;
                }
                return !(hasGetMethod && hasSetMethod);

            })
            .forEach(sqlFields::add);
        List<String> insertNames = new ArrayList<>();
        for (Field elem : sqlFields) {
            insertNames.add(elem.getName());
        }
        partSql.append("insert into ").append(tableName).append(" (");
        for (String elem : insertNames) {
            partSql.append("`").append(underscoreName(elem, false)).append("`").append(",");
        }
        if (insertNames.size() > (0)) {
            partSql.deleteCharAt(partSql.length() - 1);
        }
        partSql.append(") values ");
        partSql.toString();
    }

    public void genSql(T obj) {
        List<Object> values = new ArrayList<>();
        for (Field elem : sqlFields) {
            elem.setAccessible(true);
            Object o = ExceptionUtils.defaultApply(() -> elem.get(obj));
            values.add(o);
            elem.setAccessible(false);
        }
        appendValues(partSql, values);
    }

    public void comma() {
        partSql.append(",");
    }

    public void trim() {
        partSql.deleteCharAt(partSql.length() - 1);
    }

    public String getSql() {
        return partSql.toString();
    }

    private void appendValues(StringBuilder sqlBuilder, List<Object> values) {
        sqlBuilder.append("(");
        for (Object elem : values) {
            if (elem == null) {
                sqlBuilder.append(elem).append(",");
            } else {
                if (elem instanceof Date) {

                    sqlBuilder.append("\"").append(formatDate((Date) elem)).append("\"").append(",");
                } else {

                    sqlBuilder.append("\"").append(elem).append("\"").append(",");
                }
            }
        }
        if (values.size() > (0)) {
            sqlBuilder.deleteCharAt(sqlBuilder.length() - 1);
        }
        sqlBuilder.append(")");
    }

    private String formatDate(Date date) {
        String format = "yyyy-MM-dd HH:mm:ss";
        SimpleDateFormat format1 = new SimpleDateFormat(format);
        return format1.format(date);

    }

}